#pragma once

#include "InputProcessor.h"
#include "GameState.h"
#include "PlayersManager.h"
#include "IRaceController.h"
#include <vector>
#include <d3dx9.h>


class IGameController;
class IRenderingManager;
class IMeshStorage;
class CCollisionController;
class CInputController;
class Gate;
class ICameraImpl;
class IMovable;
class PhysicalObject;
class AIAgent;
class IRaceState;

class RaceController : public IGameState, public IPlayersManager,  public IRaceController, public IInputProcessor
{
private:
   CCollisionController* m_collisionController;
   IGameController& m_gameController;
   IRenderingManager& m_renderingManager;
   IMeshStorage& m_meshStorage;
   CInputController& m_inputController;
   ICameraImpl& m_cameraImpl;

   IRaceState* m_countdown;
   IRaceState* m_race;
   IRaceState* m_victory;
   IRaceState* m_currentState;

   IMovable* m_camera;
   PhysicalObject* m_controlledPhysicalObject;
   ActionObject* m_controlledActionObject;

   std::vector<ActionObject*> m_activePlayers;
   std::vector<ActionObject*> m_deadPlayers;
   std::vector<Gate*> m_gates;
   std::vector<AIAgent*> m_aiAgents;

   UINT m_gatesToScore;

   bool m_raceInProgress;
   bool m_hasPlayerWon;

public:
   RaceController(IGameController& gameController,
                  IRenderingManager& renderingManager,
                  IMeshStorage& meshStorage,
                  CInputController& inputController,
                  ICameraImpl& cameraImpl);

   ~RaceController();

   void update(float timeElapsed);

   void activate();

   void deactivate();

   std::vector<ActionObject*> queryForObjects(const Ray& ray);

   void removePlayer(ActionObject* object);

   PhysicalObject* getUserControllerPhysicalObject() {return m_controlledPhysicalObject;}

   ActionObject* getUserControllerActionObject() {return m_controlledActionObject;}

   Gate& getGate(UINT no) {return *(m_gates.at(no));}

   void processInput(UCHAR* keyBuffer, float timeElapsed);

   UINT getNumGatesToScore() const {return m_gatesToScore;}

   void startRace();

   void victory(UINT playerIdx);

   bool hasPlayerWon() const {return (m_raceInProgress == false) && m_hasPlayerWon;}

   void raceOver();

private:
   void removeDeadPlayers();
};
